#include "libPPD.h"
#include "N-Step-SCAN.h"

void setearFD(struct pollfd *descriptores,int32_t nroSocket)
{

	int32_t i=0;
	while(descriptores[i].fd != 0 )
	{
		i++;
	}
	descriptores[i].fd = nroSocket;
	descriptores[i].events = POLLIN;
	descriptores[i].revents = 0;

}

void recibirPedidosPRAID(struct pollfd *descriptoresLectura)
{
	extern t_log *loguear;
	extern t_config config;
	extern sem_t semaforoLista;
	extern int32_t sockConsola;
	extern int32_t socketPRAID;
	int32_t cantRespuestas=0;
	int32_t timeout_msecs = -1;
	int32_t i, j, ret, cantRecibido;
	t_NIPC paqueteRecibido;

	if ((socketPRAID = AFINET_conectar (config.dirIPpraid, config.puertoPRAID)) < 0)
		log_error (loguear, "PPD", "Message Error: %s", "No se pudo conectar al PRAID");

	ret = handshakePRAID();

	setearFD(descriptoresLectura,sockConsola);
	setearFD(descriptoresLectura,socketPRAID);

	while (1)
	{
		i=0;
		j=0;

		cantRespuestas = poll(descriptoresLectura, 2,timeout_msecs);

		while( i < 2 && j < cantRespuestas)
		{
			if (descriptoresLectura[i].revents == 17)
			{
				// Ocurrio un error, log y finalizo proceso.
				log_error (loguear, "PPD", "Message error: %s", "Se detecto un error en el poll");
				exit(0);
			}
			else if ((descriptoresLectura[i].revents & POLLIN )&& descriptoresLectura[i].fd == sockConsola)
			{
				//Recibo el pedido de la Consola y hago el switch para identificar el comando.
				ret = NIPC_recibir (sockConsola, &paqueteRecibido);
				switchConsola (paqueteRecibido);
				j++;
			}
			else if ((descriptoresLectura[i].revents & POLLIN) &&  descriptoresLectura[i].fd == socketPRAID)
			{
				//Recibo el pedido del PRAID, lo enlisto y aumento el semaforo que activa el thread ResponderPedidos.
				cantRecibido =  NIPC_recibir(descriptoresLectura[i].fd,&paqueteRecibido);
				if(cantRecibido == 0)
				{
					printf("El PRAID se ha desconectado...\n");
					raise(SIGCHLD);
					exit(0);
//					free(descriptoresLectura);
//					descriptoresLectura = NULL;
//					descriptoresLectura = (struct pollfd *)calloc(2,sizeof(struct pollfd));
//					setearFD(descriptoresLectura,sockConsola);
//					setearFD(descriptoresLectura,socketPRAID);
				}
				else if (cantRecibido == -1)
					printf("El paquete recibido está dañado\n");
				else if (cantRecibido > 0)
				{
					if (strcmp (config.algoritmo, "CLOOK") == 0)
					{
						planificarPedidoPRAID (paqueteRecibido);
						NIPC_destruirpaquete(&paqueteRecibido);
						sem_post(&semaforoLista);
					}
					else if (strcmp(config.algoritmo, "NSTEPSCAN") == 0)
						planificarN_Step_SCAN_RAID (paqueteRecibido);
					j++;
				}
			}
			i++;
		}
	}
}


void recibirPedidosPFS()
{
	extern t_config config;
	extern t_log *loguear;
	extern int32_t sockConsola;
	extern sem_t semaforoLista;
	int32_t cantRecibido=0, cantRespuestas=0,socketConexion,socketAccept;
	int32_t timeout_msecs = -1;
	int32_t i,j;
	int32_t valorRetorno;
	t_NIPC nipcRecibido;
	int32_t cantidadSockets=2;
	int32_t cantAceptados=0;

	socketConexion = AFINET_abrir_conexion(config.puertoPFS);
	struct pollfd *descriptoresLectura;
	descriptoresLectura = (struct pollfd *)calloc(cantidadSockets,sizeof(struct pollfd));

	setearFD(descriptoresLectura,sockConsola);
	setearFD(descriptoresLectura,socketConexion);

	while (1)
	{
		i=0;
		j=0;

		cantRespuestas = poll(descriptoresLectura,cantidadSockets + cantAceptados,timeout_msecs);

		while( i < cantidadSockets + cantAceptados && j < cantRespuestas)
		{
			if (descriptoresLectura[i].revents == 17)
			{
				// Ocurrio un error, log y finalizo proceso.
				log_error (loguear, "PPD", "Message error: %s", "Se detecto un error en el poll");
				exit(0);
			}
			else if ((descriptoresLectura[i].revents & POLLIN )&& descriptoresLectura[i].fd == sockConsola)
			{
				//Recibo el pedido de la Consola y hago el switch para identificar el comando.
				t_NIPC paquete;
				int32_t ret;
				ret = NIPC_recibir (sockConsola, &paquete);
				switchConsola (paquete);
				j++;
			}
			else if ((descriptoresLectura[i].revents & POLLIN) &&  descriptoresLectura[i].fd == socketConexion)
			{
                //Nuevo socket del PFS
				socketAccept = aceptar_conexion(socketConexion);
				if(cantAceptados == 0)
					valorRetorno = handshakePFS(socketAccept);
				if (valorRetorno == Retorno_OK)  //Se realizo correctamente el handshake
				{
					cantAceptados++;
					descriptoresLectura = realloc(descriptoresLectura,(cantAceptados + cantidadSockets) * sizeof(struct pollfd));
					memset(&descriptoresLectura[cantAceptados + cantidadSockets - 1],'\0',sizeof(struct pollfd));
					setearFD(descriptoresLectura,socketAccept);
					j++;
				}
			}
			else if (descriptoresLectura[i].revents & POLLIN)
			{
				//Recibo el pedido del PFS, lo enlisto y aumento el semaforo que activa el thread ResponderPedidos.
				cantRecibido =  NIPC_recibir(descriptoresLectura[i].fd,&nipcRecibido);
				if(cantRecibido == 0)
				{
					printf("El PFS se ha desconectado...\n");
					free(descriptoresLectura);
					descriptoresLectura = NULL;
					descriptoresLectura = (struct pollfd *)calloc(cantidadSockets,sizeof(struct pollfd));
					setearFD(descriptoresLectura,sockConsola);
					setearFD(descriptoresLectura,socketConexion);
					cantAceptados = 0;
				}
				else if (cantRecibido != 0)
				{
					if (strcmp (config.algoritmo, "CLOOK") == 0)
					{
						planificarPedidoPFS (nipcRecibido, descriptoresLectura[i].fd);
						NIPC_destruirpaquete(&nipcRecibido);
						sem_post(&semaforoLista);
					}
					else if (strcmp(config.algoritmo, "NSTEPSCAN") == 0)
						planificarN_Step_SCAN_PFS (nipcRecibido, descriptoresLectura[i].fd);
					j++;
				}
			}
			i++;
		}
	}
}
